﻿using ECBS_Backend.dao;
using ECBS_Backend.model;
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using System.Data;
using System.Collections;
using System.Text;
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.IO;
using Microsoft.AspNetCore.Http;
using iTextSharp.text.pdf.parser;
using ECBS_Backend.utils;

namespace ECBS_Backend.service
{
    public class GradeService
    {
        private readonly ECBSContext context;

        private HttpUtils httpUtils;

        public GradeService(ECBSContext context, HttpUtils httpUtils)
        {
            this.context = context;
            this.httpUtils = httpUtils;
        }

        /// <summary>
        /// 上传成绩证书
        /// </summary>
        /// <param name="schoolWeID"></param>
        /// <param name="studentNumber"></param>
        /// <param name="gradeDetail"></param>
        /// <returns></returns>
        public GradeClaim IssueGrade(string schoolWeID, string studentNumber, GradeDetail gradeDetail)
        {
            School school = context.Schools.SingleOrDefault(s => s.WeID == schoolWeID);
            GradeClaim grade = context.GradeClaims.FirstOrDefault(g => g.StudentNumber == studentNumber && g.SchoolName == school.Name);

            if(grade == null)
            {
                // 首次存成绩的时候
                grade = new GradeClaim();
                grade.GradeClaimId = Guid.NewGuid().ToString("N");
                grade.StudentNumber = studentNumber;

                EnrollmentClaim enrollmentClaim = context.EnrollmentClaims.FirstOrDefault(e => e.StudentNumber == studentNumber);

                if(enrollmentClaim == null)
                {
                    throw new Exception("该生还没没有学籍！");
                }

                grade.SchoolName = school.Name;
                grade.CollegeName = enrollmentClaim.CollegeName;
                grade.EnrollTime = enrollmentClaim.EnrollTime;

                List<GradeDetail> gradeDetails = new List<GradeDetail>();
                gradeDetails.Add(gradeDetail);
                grade.GradeContext = JsonConvert.SerializeObject(gradeDetails);

                // 存claim数据库
                context.GradeClaims.Add(grade);
            }
            else
            {
                // 下一次存入成绩的时候
                List<GradeDetail> gradeDetails = JsonConvert.DeserializeObject<List<GradeDetail>>(grade.GradeContext);

                foreach(GradeDetail g in gradeDetails)
                {
                    if(g.GradeName == gradeDetail.GradeName)
                    {
                        throw new Exception("该生成绩单中已有该成绩！");
                    }
                }

                gradeDetails.Add(gradeDetail);
                grade.GradeContext = JsonConvert.SerializeObject(gradeDetails);

                // 存claim数据库
                context.GradeClaims.Update(grade);
            }

            // 成绩证书上链
            string resp = httpUtils.createGradeCredential(schoolWeID, grade);

            // 上链获得返回credential信息
            GradeCredential gradeCredential = context.GradeCredentials.SingleOrDefault(g => g.StudentNumber == studentNumber);

            if(gradeCredential == null)
            {
                gradeCredential = new GradeCredential();

                gradeCredential.StudentNumber = grade.StudentNumber;
                gradeCredential.GradeCredentialContext = resp;

                // 上链返回credential信息存入数据库
                context.GradeCredentials.Add(gradeCredential);
            }
            else
            {
                gradeCredential.GradeCredentialContext = resp;

                // 上链返回credential信息存入数据库
                context.GradeCredentials.Update(gradeCredential);
            }
            

            if (context.SaveChanges() < 2)
            {
                throw new Exception("添加失败");
            }

            return grade;
        }

        /// <summary>
        /// 删除某学生的某条成绩
        /// </summary>
        /// <param name="studentNumber"></param>
        /// <param name="gradeName"></param>
        /// <param name="schoolWeID"></param>
        /// <returns></returns>
        public GradeClaim DeleteGrade(string studentNumber, string gradeName, string schoolWeID)
        {
            School school = context.Schools.SingleOrDefault(s => s.WeID == schoolWeID);
            // gradeClaim信息是否存在
            var gradeClaim = context.GradeClaims.SingleOrDefault(e => e.SchoolName == school.Name && e.StudentNumber == studentNumber);
            if (gradeClaim == null)
            {
                throw new Exception("未找到该生成绩记录");
            }

            // 修改claim的context
            List<GradeDetail> list = JsonConvert.DeserializeObject<List<GradeDetail>>(gradeClaim.GradeContext);
            var gradeDetailToRemove = list.FirstOrDefault(g => g.GradeName == gradeName);
            list.Remove(gradeDetailToRemove);
            gradeClaim.GradeContext = JsonConvert.SerializeObject(list);
            context.GradeClaims.Update(gradeClaim);


            // credential是否存在
            var gradeCredential = context.GradeCredentials.SingleOrDefault(e => e.StudentNumber == studentNumber);
            if (gradeCredential == null)
            {
                throw new Exception("未找到该生成绩证书");
            }

            // 将新的claim上链
            string resp = httpUtils.createGradeCredential(schoolWeID, gradeClaim);

            // 将获得的新credential更新到数据库
            gradeCredential.GradeCredentialContext = resp;
            context.GradeCredentials.Update(gradeCredential);

            // 数据库保存操作
            if (context.SaveChanges() <= 1)
            {
                throw new Exception("删除失败");
            }

            return gradeClaim;
        }

        /// <summary>
        /// 从数据库中获得成绩信息
        /// </summary>
        public List<GradeDetail> GetGrade(string schoolName, string studentNumber, string keyword)
        {
            try
            {
                GradeClaim gradeClaim = context.GradeClaims.SingleOrDefault(e => e.SchoolName == schoolName && e.StudentNumber == studentNumber);
                if(gradeClaim == null)
                {
                    return new List<GradeDetail>();
                }
                string gradeContext = gradeClaim.GradeContext;
                List<GradeDetail> list = JsonConvert.DeserializeObject<List<GradeDetail>>(gradeContext);
                if(keyword == null)
                {
                    return list;
                }
                list = list.FindAll((g) => g.GradeName.Contains(keyword));
                return list;
            } catch(Exception e)
            {
                throw new Exception("获得成绩出错！");
            }
        }

        /// <summary>
        /// 下载成绩信息
        /// </summary>
        public byte[] DownloadGrade(string schoolName, string studentNumber)
        {
            GradeClaim g = context.GradeClaims.SingleOrDefault(e => e.StudentNumber == studentNumber && e.SchoolName == schoolName);

            if (g == null)
            {
                throw new Exception("没有您的成绩信息，无法下载！");
            }


            DataTable dt = new DataTable();
            dt.Columns.Add("key", typeof(string));
            dt.Columns.Add("value", typeof(string));

            List<string[]> lists = new List<string[]>();
            string[] value1 = { "成绩单证书编号", g.GradeClaimId.ToString() };
            string[] value2 = { "学号", g.StudentNumber };
            string[] value3 = { "颁发时间", new DateTime((Convert.ToInt64(g.EnrollTime) * 10000) + 621355968000000000).ToString() };
            string[] value4 = { "专业名称", g.CollegeName };
            string[] value5 = { "学校名称", g.SchoolName };

            lists.Add(value1);
            lists.Add(value2);
            lists.Add(value3);
            lists.Add(value4);
            lists.Add(value5);

            List<GradeDetail> grades = GetGrade(schoolName, studentNumber, "");

            foreach(GradeDetail grade in grades)
            {
                string[] valuen = { grade.GradeName, grade.GradePoint.ToString() };
                lists.Add(valuen);
            }


            foreach (string[] s in lists)
            {
                DataRow row = dt.NewRow();
                row["key"] = s[0];
                row["value"] = s[1];
                dt.Rows.Add(row);
            }


            string path = (System.Environment.CurrentDirectory) + "/src/成绩模板.pdf";
            ConvertDataTableToPDF(dt, path, 16);


            using (FileStream fs = new FileStream(path, FileMode.Open))
            {
                byte[] bytes = new byte[(int)fs.Length];
                fs.Read(bytes, 0, bytes.Length);
                fs.Close();

                if (File.Exists(path))
                {
                    File.Delete(path);
                }

                return bytes;
            }
        }

        /// <summary>
        /// 转化pdf格式函数
        /// </summary>
        /// <param name="Data"></param>
        /// <param name="PDFFile"></param>
        /// <param name="FontSize"></param>
        /// <returns></returns>
        public bool ConvertDataTableToPDF(DataTable Data, string PDFFile, float FontSize)
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

            Document document = new Document();
            PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(PDFFile, FileMode.Create));
            document.Open();

            string path = System.Environment.CurrentDirectory + @"/src/simkai.ttf";
            BaseFont bf = BaseFont.CreateFont(path, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            iTextSharp.text.Font fontChinese = new iTextSharp.text.Font(bf, 12, iTextSharp.text.Font.NORMAL, new BaseColor(0, 0, 0));

            Font font = new Font(bf, FontSize);
            PdfPTable table = new PdfPTable(Data.Columns.Count);

            // Font font = new Font();

            table.WidthPercentage = 100;
            table.DefaultCell.Padding = 1;
            table.DefaultCell.BorderWidth = 1;
            table.DefaultCell.HorizontalAlignment = Element.ALIGN_LEFT;


            for (int i = 0; i < Data.Rows.Count; i++)
            {
                for (int j = 0; j < Data.Columns.Count; j++)
                {
                    table.AddCell(new Phrase(Data.Rows[i][j].ToString(), font));
                }
            }
            document.Add(table);
            document.Close();
            writer.Close();
            return true;
        }

        /// <summary>
        /// 验证成绩信息
        /// </summary>
        /// <returns></returns>
        public Boolean VertifyGrade(IFormFile file)
        {
            GradeClaim gradeClaim = ConvertPDFToDataTable(file);

            // 从数据库中获得credential的context
            GradeCredential gradeCredential = context.GradeCredentials.SingleOrDefault(g => g.StudentNumber == gradeClaim.StudentNumber);
            if (gradeCredential == null)
            {
                throw new Exception("该学生成绩不存在！");
            }
            string credentialContext = gradeCredential.GradeCredentialContext;
            

            // 调用rest api函数验证
            return httpUtils.verifyGrade(gradeClaim, credentialContext);
        }

        /// <summary>
        /// pdf转化为EnrollmentClaim对象
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public GradeClaim ConvertPDFToDataTable(IFormFile file)
        {
            // 验证是否是pdf文件
            var ext = System.IO.Path.GetExtension(file.FileName).ToLower();
            if (ext != ".pdf")
            {
                throw new Exception("只能上传pdf文件!");
            }


            try
            {
                // 返回的GradeClaim对象
                GradeClaim gradeClaim = new GradeClaim();

                // 生成临时文件
                var path = (Environment.CurrentDirectory) + "/src/验证成绩临时文件.pdf";
                using (var stream = new FileStream(path, FileMode.Create))
                {
                    file.CopyTo(stream);
                    stream.Close();
                }

                // 读取pdf内容
                var pdfReader = new PdfReader(path);

                ITextExtractionStrategy strategy = new SimpleTextExtractionStrategy();
                string value = PdfTextExtractor.GetTextFromPage(pdfReader, 1, strategy);
                // "成绩单账号 1\n学号 2019\n颁发时间 2001/4/4 0:00:00\n学校名称 武汉大学\n高数 95\n线代 85"
                string[] dataInfo = value.Replace("\n", "@").Split('@');


                // 成绩单账号
                int idxStart = dataInfo[0].IndexOf(" ") + 1;
                dataInfo[0] = dataInfo[0].Substring(idxStart, dataInfo[0].Length - idxStart);
                gradeClaim.GradeClaimId = dataInfo[0];

                // 学号
                idxStart = dataInfo[1].IndexOf(" ") + 1;
                dataInfo[1] = dataInfo[1].Substring(idxStart, dataInfo[1].Length - idxStart);
                gradeClaim.StudentNumber = dataInfo[1];

                // 颁发时间
                idxStart = dataInfo[2].IndexOf(" ") + 1;
                dataInfo[2] = dataInfo[2].Substring(idxStart, dataInfo[2].Length - idxStart);
                DateTime dateTime = Convert.ToDateTime(dataInfo[2]);
                DateTime startTime = TimeZoneInfo.ConvertTime(new DateTime(1970, 1, 1, 0, 0, 0, 0), TimeZoneInfo.Local);
                long t = (dateTime.Ticks - startTime.Ticks) / 10000;
                gradeClaim.EnrollTime = t;

                // 专业名称
                idxStart = dataInfo[3].IndexOf(" ") + 1;
                dataInfo[3] = dataInfo[3].Substring(idxStart, dataInfo[3].Length - idxStart);
                gradeClaim.CollegeName = dataInfo[3];

                // 学校名称
                idxStart = dataInfo[4].IndexOf(" ") + 1;
                dataInfo[4] = dataInfo[4].Substring(idxStart, dataInfo[4].Length - idxStart);
                gradeClaim.SchoolName = dataInfo[4];

                // 成绩
                string s = "[";
                for (int i = 5; i < dataInfo.Length; i++)
                {
                    idxStart = dataInfo[i].IndexOf(" ") + 1;
                    string name = dataInfo[i].Substring(0, idxStart - 1);
                    string point = dataInfo[i].Substring(idxStart, dataInfo[i].Length - idxStart);

                    s += ("{\"GradeName\":\"" + name + "\",\"GradePoint\":" + point + "}");

                    if (i != dataInfo.Length - 1)
                    {
                        s += ",";
                    }
                }
                s += "]";
                gradeClaim.GradeContext = s;

                

                pdfReader.Close();

                if (File.Exists(path))
                {
                    File.Delete(path);
                }


                return gradeClaim;
            }
            catch (Exception)
            {
                throw new Exception("您上传的pdf格式有误！");
            }
        }
    }
}
